package cmd

import (
	"fmt"
	"os"
	"time"

	"github.com/go-ping/ping"
	"github.com/spf13/cobra"
)

func onRecv(p *ping.Packet) {
	fmt.Fprintf(os.Stdout,
		"%d bytes from %s (%s): icmp_seq=%d ttl=%v time=%v\n",
		p.Nbytes, p.Addr, p.IPAddr, p.Seq, p.Ttl, p.Rtt,
	)
}

func onDuplicateRecv(p *ping.Packet) {
	fmt.Fprintf(os.Stdout,
		"%d bytes from %s (%s): icmp_seq=%d ttl=%v time=%v (DUP!)\n",
		p.Nbytes, p.Addr, p.IPAddr, p.Seq, p.Ttl, p.Rtt)
}

func onFinish(stats *ping.Statistics) {
	fmt.Fprintf(
		os.Stdout,
		"\n--- %s ping statistics ---\n", stats.Addr)
	fmt.Fprintf(
		os.Stdout,
		"%d packets transmitted, %d packets received, %d duplicates, %v%% packet loss\n",
		stats.PacketsSent, stats.PacketsRecv, stats.PacketsRecvDuplicates, stats.PacketLoss)
	fmt.Fprintf(
		os.Stdout,
		"round-trip min/avg/max/stddev = %v/%v/%v/%v\n\n",
		stats.MinRtt, stats.AvgRtt, stats.MaxRtt, stats.StdDevRtt)
}

func doPing(addr string, count, size, timeout, interval int) {
	pinger, err := ping.NewPinger(addr)
	if err != nil {
		fmt.Fprintf(os.Stdout, "toolkit ping %s: %s\n", addr, err)
	}

	pinger.Timeout = time.Second * time.Duration(timeout)
	pinger.Interval = time.Second * time.Duration(interval)
	pinger.Size = size
	pinger.Count = count

	pinger.OnRecv = onRecv
	pinger.OnDuplicateRecv = onDuplicateRecv
	pinger.OnFinish = onFinish

	// fmt.Fprintf(os.Stdout, "PING %s (%s) %d bytes of data.\n\n", addr, pinger.IPAddr(), size)

	if err := pinger.Run(); err != nil {
		fmt.Fprintf(os.Stdout, "toolkit ping %s: %s\n", addr, err)
	}
}

// nolint: gochecknoinits
func init() {
	pingCmd := &cobra.Command{
		Use:     "ping",
		Aliases: []string{"p"},
		Short:   "网络可用性检查",
		Long: `网络可用性检查

发送数据包给目标地址，检查网络是否可用.`,
		Run: func(cmd *cobra.Command, args []string) {
			c, _ := cmd.Flags().GetInt("count")
			t, _ := cmd.Flags().GetInt("timeout")
			s, _ := cmd.Flags().GetInt("size")
			i, _ := cmd.Flags().GetInt("interval")
			if len(args) == 0 {
				addr, _ := cmd.Flags().GetString("address")
				doPing(addr, c, s, t, i)

				return
			}

			for _, addr := range args {
				doPing(addr, c, s, t, i)
			}
		},
	}
	rootCmd.AddCommand(pingCmd)
	pingCmd.Flags().IntP("count", "c", 5, "测试次数")
	pingCmd.Flags().IntP("timeout", "t", 60, "超时时间(秒)")
	pingCmd.Flags().IntP("size", "s", 24, "数据包尺寸")
	pingCmd.Flags().IntP("interval", "i", 1, "间隔时间(秒)")
	pingCmd.Flags().StringP("address", "a", "gitee.com", "默认检查地址")
}
